﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DataModels.Common;
using DataModels.Enumerations;
using DataModels.Models;
using GenericTools;
using GenericTools.Models;
using GenericTools.OptionBPlus;
using ReportingManagement.Components.DHIS;

namespace ReportingManagement.Components
{
    /// <summary>
    /// Interaction logic for LDMTUHAReport.xaml
    /// </summary>
    public partial class LDMTUHAReport : UserControl
    {
        public event EventHandler<InteroperableUserControlEventArgs> StatusChanged;

        private enum Direction
        {
            UP, DOWN, LEFT, RIGHT
        }

        /// <summary>
        /// View mode
        /// </summary>
        public enum ViewMode
        {
            /// <summary>
            /// Editing
            /// </summary>
            EDITING = 1,

            /// <summary>
            /// Read-only
            /// </summary>
            READ_ONLY = 2
        }

        private FullLDMTUHAReport mtuhaReport;
        private UserInformation user;
        private BackgroundWorker backgroundWorker;

        private ViewMode _mode;
        public ViewMode Mode
        {
            get { return _mode; }
            set
            {
                _mode = value;
                UpdateViewMode();
            }
        }

        private void UpdateViewMode()
        {
            switch (_mode)
            {
                case LDMTUHAReport.ViewMode.EDITING:
                    btnGetReport.Visibility = System.Windows.Visibility.Collapsed;
                    gridActionPanel.Visibility = System.Windows.Visibility.Visible;
                    foreach (UIElement element in grid.Children)
                    {
                        var textBox = element as TextBox;
                        if (textBox != null) if (textBox.Focusable) textBox.IsReadOnly = false;
                    }
                    break;

                case LDMTUHAReport.ViewMode.READ_ONLY:
                    btnGetReport.Visibility = System.Windows.Visibility.Visible;
                    gridActionPanel.Visibility = System.Windows.Visibility.Collapsed;
                    foreach (UIElement element in grid.Children)
                    {
                        var textBox = element as TextBox;
                        if (textBox != null) if (textBox.Focusable) textBox.IsReadOnly = true;
                    }
                    break;
            }
        }

        // Making sure this is set up in the codes
        [Browsable(false)]
        public UserInformation User
        {
            get { return this.user; }
            set
            {
                this.user = value;
                if (regions == null)
                {
                    progressBar.Visibility = Visibility.Visible;
                    lblProgress.Visibility = Visibility.Visible;
                    cboRegion.IsEnabled = false;
                    cboDistrict.IsEnabled = false;
                    cboFacility.IsEnabled = false;
                    cboReportYear.IsEnabled = false;
                    cboReportMonth.IsEnabled = false;
                    btnGetReport.IsEnabled = false;
                    btnSave.IsEnabled = false;
                    btnReset.IsEnabled = false;
                    loadingRegions = true;
                    backgroundWorker.RunWorkerAsync();
                    var args = new InteroperableUserControlEventArgs
                    {
                        StatusText = "Loading regions, districts and facilities. Please wait...",
                        Type = InteroperableUserControlEventArgs.StatusType.Text
                    };
                    if (StatusChanged != null) StatusChanged(this, args);
                }
                else
                {
                    cboRegion.ItemsSource = regions;
                    PopulateMonthList();
                    PopulateYearList();
                    InitializeNewReportInstance();

                    progressBar.Visibility = Visibility.Collapsed;
                    lblProgress.Visibility = Visibility.Collapsed;
                    cboRegion.IsEnabled = true;
                    cboDistrict.IsEnabled = true;
                    cboFacility.IsEnabled = true;
                    cboReportYear.IsEnabled = true;
                    cboReportMonth.IsEnabled = true;
                    btnGetReport.IsEnabled = true;
                    btnSave.IsEnabled = true;
                    btnReset.IsEnabled = true;
                }
            }
        }

        public void Reload(FullLDMTUHAReport newReport, bool disableLocation, bool disableReportTime)
        {
            if (newReport.Above20Form == null)
            {
                newReport.Above20Form = new LDForm();
                newReport.Above20Form.LessThan20 = false;
            }

            if (newReport.Under20Form == null)
            {
                newReport.Under20Form = new LDForm();
                newReport.Under20Form.LessThan20 = true;
            }

            PrepareReportBeforeLink(newReport.Under20Form);
            PrepareReportBeforeLink(newReport.Above20Form);

            mtuhaReport = newReport;
            //this.DataContext = null;
            this.DataContext = newReport;

            if (disableLocation)
            {
                cboRegion.IsEnabled = false;
                cboDistrict.IsEnabled = false;
                cboFacility.IsEnabled = false;
            }

            if (disableReportTime)
            {
                cboReportMonth.IsEnabled = false;
                cboReportYear.IsEnabled = false;
            }
        }

        private void PrepareReportBeforeLink(LDForm report)
        {
            if (report.LDForm_TaarifaYaWaliojifungua == null) report.LDForm_TaarifaYaWaliojifungua = new LDForm_TaarifaYaWaliojifungua();
            if (report.LDForm_NjiaYaKujifungua == null) report.LDForm_NjiaYaKujifungua = new LDForm_NjiaYaKujifungua();
            if (report.LDForm_MatatizoKablaYaKujifungua == null) report.LDForm_MatatizoKablaYaKujifungua = new LDForm_MatatizoKablaYaKujifungua();
            if (report.LDForm_MatatizoBaadaYaKujifungua == null) report.LDForm_MatatizoBaadaYaKujifungua = new LDForm_MatatizoBaadaYaKujifungua();
            if (report.LDForm_EmOC == null) report.LDForm_EmOC = new LDForm_EmOC();
            if (report.LDForm_PMTCT == null) report.LDForm_PMTCT = new LDForm_PMTCT();
            if (report.LDForm_WatotoWaliozaliwaMmoja == null) report.LDForm_WatotoWaliozaliwaMmoja = new LDForm_WatotoWaliozaliwaMmoja();
            if (report.LDForm_WatotoWaliozaliwaMapacha == null) report.LDForm_WatotoWaliozaliwaMapacha = new LDForm_WatotoWaliozaliwaMapacha();
            if (report.LDForm_WatotoWaliosaidiwaKupumua == null) report.LDForm_WatotoWaliosaidiwaKupumua = new LDForm_WatotoWaliosaidiwaKupumua();
        }

        public void EnableLocationEdition(bool enabled)
        {
            cboRegion.IsEnabled = enabled;
            cboDistrict.IsEnabled = enabled;
            cboFacility.IsEnabled = enabled;
        }

        public void EnableReportTimeEditing(bool enabled)
        {
            cboReportMonth.IsEnabled = enabled;
            cboReportYear.IsEnabled = enabled;
        }

        private static List<Region> regions = null;
        bool savingReport = false;
        bool gettingReport = false;
        bool loadingRegions = false;
        bool autoUploadToDHIS = true;
        public LDMTUHAReport()
        {
            InitializeComponent();
            progressBar.Visibility = Visibility.Collapsed;
            lblProgress.Visibility = Visibility.Collapsed;

            backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += backgroundWorker_DoWork;
            backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
        }

        public LDMTUHAReport(UserInformation user)
        {
            InitializeComponent();
            progressBar.Visibility = Visibility.Collapsed;
            lblProgress.Visibility = Visibility.Collapsed;

            backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += backgroundWorker_DoWork;
            backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;

            if (regions == null) regions = Utilities.GetDetailedAllRegions(user.SupportingPartnerId, user.UserSignature);
            cboRegion.ItemsSource = regions;
            this.user = user;

            //LoadListOfRegions();
            PopulateMonthList();
            PopulateYearList();
            InitializeNewReportInstance();
        }

        void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

            var args = new InteroperableUserControlEventArgs
            {
                StatusText = "Ready",
                Type = InteroperableUserControlEventArgs.StatusType.Text
            };
            if (StatusChanged != null) StatusChanged(this, args);

            #region Saving Operation
            if (savingReport)
            {
                savingReport = false;
                if (e.Error != null)
                {
                    MessageBox.Show(e.Error.Message, AppConfiguration.ApplicationName,
                        MessageBoxButton.OK, MessageBoxImage.Error);
                    btnSave.Content = "Save Changes";
                    btnSave.IsEnabled = true;
                    args = new InteroperableUserControlEventArgs
                    {
                        StatusText = e.Error.Message,
                        Type = InteroperableUserControlEventArgs.StatusType.Text
                    };
                    if (StatusChanged != null) StatusChanged(this, args);
                    return;
                }

                var status = e.Result as ReportingError;
                if (status != null)
                {
                    MessageBoxImage icon = MessageBoxImage.Information;
                    if (status.Type != DataModels.Common.ReportProcessingError.NO_ERROR)
                    {
                        icon = MessageBoxImage.Error;
                    }
                    MessageBox.Show(status.ErrorText, AppConfiguration.ApplicationName,
                            MessageBoxButton.OK, icon);
                }
                else
                {
                    MessageBox.Show("Invalid operation status. It may be caused by old version. " +
                        "\nTry to update then repeat this operation.");
                }

                btnSave.Content = "Save Changes";
                btnSave.IsEnabled = true;
            }
            #endregion

            #region Getting Report
            if (gettingReport)
            {
                gettingReport = false;
                if (e.Error != null)
                {
                    MessageBox.Show(e.Error.Message, AppConfiguration.ApplicationName,
                        MessageBoxButton.OK, MessageBoxImage.Error);
                    btnGetReport.Content = "Get Report";
                    btnGetReport.IsEnabled = true;
                    btnReset.Content = "Reset or Retrieve Existing Report";
                    btnReset.IsEnabled = true;
                    args = new InteroperableUserControlEventArgs
                    {
                        StatusText = e.Error.Message,
                        Type = InteroperableUserControlEventArgs.StatusType.Text
                    };
                    if (StatusChanged != null) StatusChanged(this, args);
                    return;
                }

                var mtuhaReport = e.Result as FullLDMTUHAReport;
                if (mtuhaReport != null)
                {
                    this.Reload(mtuhaReport, false, false);
                }
                else
                {
                    MessageBox.Show("Invalid operation status. It may be caused by old version. " +
                            "\nTry to update then repeat this operation.");
                }
                btnGetReport.Content = "Get Report";
                btnGetReport.IsEnabled = true;
                btnReset.Content = "Reset or Retrieve Existing Report";
                btnReset.IsEnabled = true;
            }
            #endregion

            #region Loading Regions
            if (loadingRegions)
            {
                loadingRegions = false;
                if (e.Error != null)
                {
                    progressBar.Visibility = Visibility.Collapsed;
                    lblProgress.HorizontalContentAlignment = HorizontalAlignment.Left;
                    lblProgress.Content = e.Error.Message;
                    lblProgress.FontWeight = FontWeights.Normal;
                    lblProgress.Foreground = Brushes.Red;

                    btnRetryLoadingRegions.Visibility = Visibility.Visible;
                    args = new InteroperableUserControlEventArgs
                    {
                        StatusText = e.Error.Message,
                        Type = InteroperableUserControlEventArgs.StatusType.Text
                    };
                    if (StatusChanged != null) StatusChanged(this, args);
                    return;
                }

                regions = e.Result as List<Region>;
                if (regions != null)
                {
                    cboRegion.ItemsSource = regions;
                    PopulateMonthList();
                    PopulateYearList();
                    InitializeNewReportInstance();

                    progressBar.Visibility = Visibility.Collapsed;
                    lblProgress.Visibility = Visibility.Collapsed;
                    cboRegion.IsEnabled = true;
                    cboDistrict.IsEnabled = true;
                    cboFacility.IsEnabled = true;
                    cboReportYear.IsEnabled = true;
                    cboReportMonth.IsEnabled = true;
                    btnGetReport.IsEnabled = true;
                    btnSave.IsEnabled = true;
                    btnReset.IsEnabled = true;
                }
            }
            #endregion
        }

        void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (savingReport)
            {
                var reportingText = CreateReportingText();
                if (!string.IsNullOrWhiteSpace(reportingText))
                {
                    string username = this.user.Username;
                    string password = DataTransformation.Encrypt(this.user.Password);

                    string authorizationText = null;
                    if (autoUploadToDHIS) authorizationText = DHISDataBridge.DefaultAuthorizationAgent.AuthorizationText;
                    var status = Utilities.SaveMTUHAReport(reportingText, username, password,
                        mtuhaReport.Above20Form.Comments, autoUploadToDHIS, authorizationText); 
                    e.Result = status;
                }
            }

            if (gettingReport)
            {
                string facilityCode = this.mtuhaReport.FacilityCode;
                int year = this.mtuhaReport.ReportYear;
                int month = this.mtuhaReport.ReportMonth;
                int districtId = this.mtuhaReport.DistrictId;
                int regionId = this.mtuhaReport.RegionId;

                var under20Report = Utilities.GetLDMTUHAReport(facilityCode, year, month, true);
                var above20Report = Utilities.GetLDMTUHAReport(facilityCode, year, month, false);

                var mtuhaReport = new FullLDMTUHAReport
                {
                    FacilityCode = facilityCode,
                    DistrictId = districtId,
                    RegionId = regionId,

                    ReportMonth = month,
                    ReportYear = year,

                    Under20Form = under20Report,
                    Above20Form = above20Report
                };

                e.Result = mtuhaReport;
            }

            if (loadingRegions)
            {
                if (regions == null)
                {
                    var results = Utilities.GetDetailedAllRegions(this.user.SupportingPartnerId, this.user.UserSignature);
                    e.Result = results;
                }
                else e.Result = regions;
            }
        }

        private void LoadListOfRegions()
        {
            DataTable dataTable = null;
            Cursor = Cursors.Wait;

            switch (this.user.Level)
            {
                case DataModels.Enumerations.AccessLevel.FACILITY:
                    string facilityCode = this.user.AccessLevelValue;
                    dataTable = Utilities.GetFacilityRegion(facilityCode);
                    //dataTable = Utilities.GetFacilityDetails(facilityCode);
                    break;

                case DataModels.Enumerations.AccessLevel.DISTRICT:
                    int districtID = Int32.Parse(this.user.AccessLevelValue);
                    dataTable = Utilities.GetDistrictRegion(districtID);
                    //dataTable = Utilities.GetFacilitiesDetailsByDistrict(districtID);
                    break;

                case DataModels.Enumerations.AccessLevel.REGION:
                    int regionID = Int32.Parse(this.user.AccessLevelValue);
                    dataTable = Utilities.GetRegion(regionID);
                    //dataTable = Utilities.GetFacilitiesDetailsByRegion(regionID);
                    break;

                case DataModels.Enumerations.AccessLevel.NATION:
                    dataTable = Utilities.GetAllRegions(this.user.SupportingPartnerId);
                    break;

                case DataModels.Enumerations.AccessLevel.ADMINISTRATOR:
                    //dataTable = Utilities.GetAllFacilities();
                    dataTable = Utilities.GetAllRegions();
                    break;
            }
            Cursor = Cursors.Arrow;

            cboRegion.SelectedValuePath = "RegionID";
            cboRegion.DisplayMemberPath = "RegionName";
            cboRegion.ItemsSource = dataTable.DefaultView;
            if (cboRegion.Items.Count > 0) cboRegion.SelectedIndex = 0;
        }

        private void PopulateMonthList()
        {
            DataTable dataTable = new DataTable();
            DataColumn column = new DataColumn("Period", Type.GetType("System.Int32"));
            dataTable.Columns.Add(column);
            column = new DataColumn("Month", Type.GetType("System.String"));
            dataTable.Columns.Add(column);

            DataRow row = null;
            for (int i = 1; i < 13; i++)
            {
                row = dataTable.NewRow();
                row["Period"] = i;
                row["Month"] = Utilities.GetMonthText(i);
                dataTable.Rows.Add(row);
            }

            cboReportMonth.SelectedValuePath = "Period";
            cboReportMonth.DisplayMemberPath = "Month";
            cboReportMonth.ItemsSource = dataTable.DefaultView;
        }

        private void PopulateYearList()
        {
            DataTable dataTable = new DataTable();
            DataColumn column = new DataColumn("Year", Type.GetType("System.Int32"));
            dataTable.Columns.Add(column);

            int currentYear = DateTime.Now.Year;
            DataRow row = dataTable.NewRow();
            row["Year"] = currentYear;
            dataTable.Rows.Add(row);

            row = dataTable.NewRow();
            row["Year"] = currentYear - 1;
            dataTable.Rows.Add(row);

            cboReportYear.DisplayMemberPath = "Year";
            cboReportYear.SelectedValuePath = "Year";
            cboReportYear.ItemsSource = dataTable.DefaultView;
        }

        private void InitializeNewReportInstance()
        {
            this.DataContext = null;
            var lastMonth = DateTime.Now.AddMonths(-1);
            this.mtuhaReport = new FullLDMTUHAReport
            {
                ReportMonth = lastMonth.Month,
                ReportYear = lastMonth.Year,

                Under20Form = new LDForm
                {
                    C_1 = 0,
                    C_5 = 0,
                    C_13 = 0,
                    C_12 = 0,
                    C_14 = 0,
                    LDForm_TaarifaYaWaliojifungua = new LDForm_TaarifaYaWaliojifungua(),
                    LDForm_NjiaYaKujifungua = new LDForm_NjiaYaKujifungua(),
                    LDForm_MatatizoKablaYaKujifungua = new LDForm_MatatizoKablaYaKujifungua(),
                    LDForm_MatatizoBaadaYaKujifungua = new LDForm_MatatizoBaadaYaKujifungua(),
                    LDForm_EmOC = new LDForm_EmOC(),
                    LDForm_PMTCT = new LDForm_PMTCT(),
                    LDForm_WatotoWaliozaliwaMmoja = new LDForm_WatotoWaliozaliwaMmoja(),
                    LDForm_WatotoWaliozaliwaMapacha = new LDForm_WatotoWaliozaliwaMapacha(),
                    LDForm_WatotoWaliosaidiwaKupumua = new LDForm_WatotoWaliosaidiwaKupumua()
                },

                Above20Form = new LDForm
                {
                    C_1 = 0,
                    C_5 = 0,
                    C_13 = 0,
                    C_12 = 0,
                    C_14 = 0,
                    LDForm_TaarifaYaWaliojifungua = new LDForm_TaarifaYaWaliojifungua(),
                    LDForm_NjiaYaKujifungua = new LDForm_NjiaYaKujifungua(),
                    LDForm_MatatizoKablaYaKujifungua = new LDForm_MatatizoKablaYaKujifungua(),
                    LDForm_MatatizoBaadaYaKujifungua = new LDForm_MatatizoBaadaYaKujifungua(),
                    LDForm_EmOC = new LDForm_EmOC(),
                    LDForm_PMTCT = new LDForm_PMTCT(),
                    LDForm_WatotoWaliozaliwaMmoja = new LDForm_WatotoWaliozaliwaMmoja(),
                    LDForm_WatotoWaliozaliwaMapacha = new LDForm_WatotoWaliozaliwaMapacha(),
                    LDForm_WatotoWaliosaidiwaKupumua = new LDForm_WatotoWaliosaidiwaKupumua()
                }
            };
            this.DataContext = mtuhaReport;
            LinkIndicatorsWithinForm();
        }

        private void LoadEmptyForm()
        {
            if (cboFacility.SelectedItem != null)
            {
                this.mtuhaReport = new FullLDMTUHAReport
                {
                    ReportMonth = int.Parse(cboReportMonth.SelectedValue.ToString()),
                    ReportYear = int.Parse(cboReportYear.SelectedValue.ToString()),
                    RegionId = int.Parse(cboRegion.SelectedValue.ToString()),
                    DistrictId = int.Parse(cboDistrict.SelectedValue.ToString()),
                    FacilityCode = cboFacility.SelectedValue.ToString(),

                    Under20Form = new LDForm
                    {
                        C_1 = 0,
                        C_5 = 0,
                        C_13 = 0,
                        C_12 = 0,
                        C_14 = 0,
                        LDForm_TaarifaYaWaliojifungua = new LDForm_TaarifaYaWaliojifungua(),
                        LDForm_NjiaYaKujifungua = new LDForm_NjiaYaKujifungua(),
                        LDForm_MatatizoKablaYaKujifungua = new LDForm_MatatizoKablaYaKujifungua(),
                        LDForm_MatatizoBaadaYaKujifungua = new LDForm_MatatizoBaadaYaKujifungua(),
                        LDForm_EmOC = new LDForm_EmOC(),
                        LDForm_PMTCT = new LDForm_PMTCT(),
                        LDForm_WatotoWaliozaliwaMmoja = new LDForm_WatotoWaliozaliwaMmoja(),
                        LDForm_WatotoWaliozaliwaMapacha = new LDForm_WatotoWaliozaliwaMapacha(),
                        LDForm_WatotoWaliosaidiwaKupumua = new LDForm_WatotoWaliosaidiwaKupumua()
                    },

                    Above20Form = new LDForm
                    {
                        C_1 = 0,
                        C_5 = 0,
                        C_13 = 0,
                        C_12 = 0,
                        C_14 = 0,
                        LDForm_TaarifaYaWaliojifungua = new LDForm_TaarifaYaWaliojifungua(),
                        LDForm_NjiaYaKujifungua = new LDForm_NjiaYaKujifungua(),
                        LDForm_MatatizoKablaYaKujifungua = new LDForm_MatatizoKablaYaKujifungua(),
                        LDForm_MatatizoBaadaYaKujifungua = new LDForm_MatatizoBaadaYaKujifungua(),
                        LDForm_EmOC = new LDForm_EmOC(),
                        LDForm_PMTCT = new LDForm_PMTCT(),
                        LDForm_WatotoWaliozaliwaMmoja = new LDForm_WatotoWaliozaliwaMmoja(),
                        LDForm_WatotoWaliozaliwaMapacha = new LDForm_WatotoWaliozaliwaMapacha(),
                        LDForm_WatotoWaliosaidiwaKupumua = new LDForm_WatotoWaliosaidiwaKupumua()
                    }
                };
                this.DataContext = mtuhaReport;
                LinkIndicatorsWithinForm();
            }
        }

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox textBox = (TextBox)e.OriginalSource;
            // Find the grid row where this item belongs
            int targetRow = Grid.GetRow(textBox);
            const int UNDER_20_COLUMN_INDEX = 2;
            const int ABOVE_20_COLUMN_INDEX = 3;
            const int TOTAL_COLUMN_INDEX = 4;

            TextBox under20 = null, above20 = null;
            Label total = null;
            int count = 0;
            foreach (UIElement element in grid.Children)
            {
                int rowIndex = Grid.GetRow(element);
                if (rowIndex == targetRow)
                {
                    int columnIndex = Grid.GetColumn(element);
                    if (columnIndex == UNDER_20_COLUMN_INDEX)
                    {
                        under20 = element as TextBox;
                        count++;
                    }
                    if (columnIndex == ABOVE_20_COLUMN_INDEX)
                    {
                        above20 = element as TextBox;
                        count++;
                    }
                    if (columnIndex == TOTAL_COLUMN_INDEX)
                    {
                        total = element as Label;
                        count++;
                    }
                }
                if (count == 3) break;
            }

            if (under20 != null && above20 != null && total != null)
            {
                if (total.Tag != null)
                {
                    if (total.Tag.ToString() == "%")
                    {
                        decimal num, den;
                        decimal.TryParse(lblPercentageNum.Content.ToString(), out num);
                        decimal.TryParse(lblPercentageDen.Content.ToString(), out den);
                        int percentage = 0;
                        if (den != 0) percentage = (int)((num / den) * 100);
                        total.Content = percentage;
                        return;
                    }
                }

                int iUnder20;
                int iAbove20;
                int iTotal;
                bool okToContinue = int.TryParse(under20.Text, out iUnder20);
                if (!okToContinue) iUnder20 = 0;

                okToContinue = okToContinue = int.TryParse(above20.Text, out iAbove20);
                if (!okToContinue) iAbove20 = 0;

                iTotal = iUnder20 + iAbove20;
                total.Content = iTotal;
            }
        }

        private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            TextBox textBox = null;
            int targetColumnIndex;
            int targetRowIndex;
            Direction direction;
            switch (e.Key)
            {
                case Key.Down:
                    direction = Direction.DOWN;
                    textBox = (TextBox)e.OriginalSource;
                    targetColumnIndex = Grid.GetColumn(textBox);
                    targetRowIndex = Grid.GetRow(textBox) + 1;
                    if (grid.RowDefinitions.Count == targetRowIndex) return;
                    else
                    {
                        SetFocusToTheNextTextBox(targetRowIndex, targetColumnIndex, direction);
                        e.Handled = true;
                    }
                    break;

                case Key.Up:
                    direction = Direction.UP;
                    textBox = (TextBox)e.OriginalSource;
                    targetColumnIndex = Grid.GetColumn(textBox);
                    targetRowIndex = Grid.GetRow(textBox) - 1;
                    if (targetRowIndex == -1) return;
                    else
                    {
                        SetFocusToTheNextTextBox(targetRowIndex, targetColumnIndex, direction);
                        e.Handled = true;
                    }
                    break;

                case Key.Left:
                    direction = Direction.LEFT;
                    textBox = (TextBox)e.OriginalSource;
                    targetColumnIndex = Grid.GetColumn(textBox) - 1;
                    targetRowIndex = Grid.GetRow(textBox);
                    if (targetColumnIndex == -1) return;
                    else
                    {
                        SetFocusToTheNextTextBox(targetRowIndex, targetColumnIndex, direction);
                        e.Handled = true;
                    }
                    break;

                case Key.Right:
                    direction = Direction.RIGHT;
                    textBox = (TextBox)e.OriginalSource;
                    targetColumnIndex = Grid.GetColumn(textBox) + 1;
                    targetRowIndex = Grid.GetRow(textBox);
                    if (grid.ColumnDefinitions.Count == targetColumnIndex) return;
                    else
                    {
                        SetFocusToTheNextTextBox(targetRowIndex, targetColumnIndex, direction);
                        e.Handled = true;
                    }
                    break;
            }
        }

        private void SetFocusToTheNextTextBox(int targetRowIndex, int targetColumnIndex, Direction direction)
        {
            bool repeatSearch = default(bool);
            do
            {
                repeatSearch = SearchNextTextBox(targetRowIndex, targetColumnIndex);
                if (direction == Direction.DOWN) targetRowIndex++;
                if (direction == Direction.UP) targetRowIndex--;
                if (direction == Direction.LEFT) targetColumnIndex--;
                if (direction == Direction.RIGHT) targetColumnIndex++;
            } while (repeatSearch);
        }

        private bool SearchNextTextBox(int targetRowIndex, int targetColumnIndex)
        {
            const int LABEL_ROW_SPAN = 4;
            bool repeatSearch = false;
            foreach (UIElement element in grid.Children)
            {
                int rowIndex = Grid.GetRow(element);
                if (rowIndex == targetRowIndex)
                {
                    int columnIndex = Grid.GetColumn(element);
                    if (columnIndex == targetColumnIndex)
                    {
                        var textBox = element as TextBox;
                        if (textBox != null)
                        {
                            if (textBox.IsReadOnly) repeatSearch = true;
                            else
                            {
                                textBox.Focus();
                                textBox.SelectAll();
                                return false;
                            }
                        }
                    }
                    else
                    {
                        var label = element as Label;
                        if (label != null)
                        {
                            int columnSpan = Grid.GetColumnSpan(label);
                            if (columnSpan == LABEL_ROW_SPAN)
                            {
                                // Re-construct the target row to be the next
                                repeatSearch = true;
                            }
                        }
                    }
                }
            }
            return repeatSearch;
        }

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (this.mtuhaReport != null)
                {
                    if (cboFacility.SelectedItem != null && cboReportMonth.SelectedItem != null
                        && cboReportYear.SelectedItem != null)
                    {
                        foreach (UIElement element in grid.Children)
                        {
                            TextBox textBox = element as TextBox;
                            if (textBox != null)
                            {
                                if (string.IsNullOrWhiteSpace(textBox.Text))
                                {
                                    textBox.Focus();
                                    MessageBox.Show("Please fill all the required fields", "Incomplete Form",
                                        MessageBoxButton.OK, MessageBoxImage.Warning);
                                    return;
                                }
                            }
                        }

                        autoUploadToDHIS = true;   // Default is auto-upload
                        if (chbAutoUpload.IsChecked.HasValue)
                        {
                            if (chbAutoUpload.IsChecked.Value)
                            {
                                if (DHISDataBridge.DefaultAuthorizationAgent == null)
                                {
                                    DHISDataBridge.DefaultBaseUrl = AppConfiguration.DHISBaseUrl;
                                    var dhisLogin = new DHISLogin();
                                    dhisLogin.ShowInTaskbar = true;
                                    bool? result = dhisLogin.ShowDialog();

                                    if (result.HasValue && result.Value) DHISDataBridge.DefaultAuthorizationAgent = dhisLogin.Agent;
                                    else return;
                                }
                            }
                            else autoUploadToDHIS = false;
                        }

                        savingReport = true;
                        backgroundWorker.RunWorkerAsync();
                        btnSave.Content = "Please wait...";
                        btnSave.IsEnabled = false;
                        var args = new InteroperableUserControlEventArgs
                        {
                            StatusText = "Please wait...",
                            Type = InteroperableUserControlEventArgs.StatusType.Text
                        };
                        if (StatusChanged != null) StatusChanged(this, args);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, AppConfiguration.ApplicationName,
                    MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        #region Creation of Reporting Text
        private string CreateReportingText()
        {
            string reportKeywords = GenericTools.Utilities.GetSetting(LDFormValidator.SETTINGS_KEY_LD_MTUHA_REPORT_KEYWORDS);
            if (string.IsNullOrEmpty(reportKeywords))
            {
                GenericTools.Utilities.SetSetting(LDFormValidator.SETTINGS_KEY_LD_MTUHA_REPORT_KEYWORDS, LDFormValidator.DEFAULT_LD_MTUHA_REPORT_KEYWORDS);
                reportKeywords = LDFormValidator.DEFAULT_LD_MTUHA_REPORT_KEYWORDS;
            }

            string keyword = reportKeywords.Split('|')[0];
            string facilityCode = this.mtuhaReport.FacilityCode;
            int year = this.mtuhaReport.ReportYear;
            int month = this.mtuhaReport.ReportMonth;

            string segmentPrefix = Utilities.GetSetting(FormValidator.SETTINGS_KEY_MTUHA_REPORT_SECTION_KEYWORD);
            string under20Keyword = Utilities.GetSetting(FormValidator.SETTINGS_KEY_MTUHA_REPORT_UNDER_20_KEYWORD);
            string above20Keyword = Utilities.GetSetting(FormValidator.SETTINGS_KEY_MTUHA_REPORT_ABOVE_20_KEYWORD);

            string mainFormUnder20 = GetSegmentForMainReport(under20Keyword, segmentPrefix, mtuhaReport.Under20Form);
            string mainFormAbove20 = GetSegmentForMainReport(above20Keyword, segmentPrefix, mtuhaReport.Above20Form);

            string taarifaYaWaliojifunguaUnder20 = Method2(under20Keyword, segmentPrefix,
                mtuhaReport.Under20Form.LDForm_TaarifaYaWaliojifungua);
            string taarifaYaWaliojifunguaAbove20 = Method2(above20Keyword, segmentPrefix,
                mtuhaReport.Above20Form.LDForm_TaarifaYaWaliojifungua);

            string njiaZaKujifunguaUnder20 = Method2(under20Keyword, segmentPrefix,
                mtuhaReport.Under20Form.LDForm_NjiaYaKujifungua);
            string njiaZaKujifunguaAbove20 = Method2(above20Keyword, segmentPrefix,
                mtuhaReport.Above20Form.LDForm_NjiaYaKujifungua);

            string matatizoKablaUnder20 = Method2(under20Keyword, segmentPrefix,
                mtuhaReport.Under20Form.LDForm_MatatizoKablaYaKujifungua);
            string matatizoKablaAbove20 = Method2(above20Keyword, segmentPrefix,
                mtuhaReport.Above20Form.LDForm_MatatizoKablaYaKujifungua);

            string matatizoBaadaUnder20 = Method2(under20Keyword, segmentPrefix,
                mtuhaReport.Under20Form.LDForm_MatatizoBaadaYaKujifungua);
            string matatizoBaadaAbove20 = Method2(above20Keyword, segmentPrefix,
                mtuhaReport.Above20Form.LDForm_MatatizoBaadaYaKujifungua);

            string emocUnder20 = Method2(under20Keyword, segmentPrefix, mtuhaReport.Under20Form.LDForm_EmOC);
            string emocAbove20 = Method2(above20Keyword, segmentPrefix, mtuhaReport.Above20Form.LDForm_EmOC);

            string pmtctUnder20 = Method2(under20Keyword, segmentPrefix, mtuhaReport.Under20Form.LDForm_PMTCT);
            string pmtctAbove20 = Method2(above20Keyword, segmentPrefix, mtuhaReport.Above20Form.LDForm_PMTCT);

            string watotoWaliozaliwaUnder20 = Method2(under20Keyword, segmentPrefix,
                mtuhaReport.Under20Form.LDForm_WatotoWaliozaliwaMmoja);
            string watotoWaliozaliwaAbove20 = Method2(above20Keyword, segmentPrefix,
                mtuhaReport.Above20Form.LDForm_WatotoWaliozaliwaMmoja);

            string mapachaWaliozaliwaUnder20 = Method2(under20Keyword, segmentPrefix,
                mtuhaReport.Under20Form.LDForm_WatotoWaliozaliwaMapacha);
            string mapachaWaliozaliwaAbove20 = Method2(above20Keyword, segmentPrefix, 
                mtuhaReport.Above20Form.LDForm_WatotoWaliozaliwaMapacha);

            string watotoWaliosaidiwaUnder20 = Method2(under20Keyword, segmentPrefix,
                mtuhaReport.Under20Form.LDForm_WatotoWaliosaidiwaKupumua);
            string watotoWaliosaidiwaAbove20 = Method2(above20Keyword, segmentPrefix,
                mtuhaReport.Above20Form.LDForm_WatotoWaliosaidiwaKupumua);

            string reportingText = string.Format(
                "{0}.{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20},{21},{22},{23}",
                keyword, facilityCode, month, year, 
                mainFormUnder20, mainFormAbove20,
                taarifaYaWaliojifunguaUnder20, taarifaYaWaliojifunguaAbove20,
                njiaZaKujifunguaUnder20, njiaZaKujifunguaAbove20,
                matatizoKablaUnder20, matatizoKablaAbove20,
                matatizoBaadaUnder20, matatizoBaadaAbove20,
                emocUnder20, emocAbove20,
                pmtctUnder20, pmtctAbove20,
                watotoWaliozaliwaUnder20, watotoWaliozaliwaAbove20,
                mapachaWaliozaliwaUnder20, mapachaWaliozaliwaAbove20,
                watotoWaliosaidiwaUnder20, watotoWaliosaidiwaAbove20);

            return reportingText;
        }

        private static string GetSegmentForMainReport(string ageCategoryKeyword, string segmentPrefix, LDForm form)
        {
            //C20,K1,1,K3,2,K7,3,K8,4,K9,5,K10,6
            return string.Format("{0},{1}1,{2},{0},{1}5,{3},{0},{1}12,{4},{0},{1}13,{5},{0},{1}14,{6}",
                ageCategoryKeyword, segmentPrefix,
                form.C_1, form.C_5, form.C_12, form.C_13, form.C_14);
        }

        //private static string GetHudhurioLaKwanzaSegment(string ageCategoryKeyword, string segmentPrefix,
        //    ANCForm_HudhurioLaKwanza form)
        //{
        //    return string.Format("{0},{1}2,{2},{3},{4},{5},{6},{7},{8}",
        //        ageCategoryKeyword, segmentPrefix,
        //        form.C_2a, form.C_2b, form.C_2c, form.C_2d, form.C_2e, form.C_2f, form.C_2g);
        //}

        private static string Method2(string ageCategoryKeyword, string segmentPrefix,
            MTUHAReportBase formSectionData)
        {
            bool sectionNumberFound = false;
            var sBuilder = new StringBuilder();

            var properties = formSectionData.GetType().GetProperties();
            foreach (var property in properties)
            {
                if (property.Name.StartsWith("C_", StringComparison.OrdinalIgnoreCase))
                {
                    if (!sectionNumberFound)
                    {
                        string sectionNumber =  Regex.Match(property.Name, @"\d+").Value;
                        sBuilder.Append(ageCategoryKeyword + "," + segmentPrefix + sectionNumber);
                        sectionNumberFound = true;
                    }
                    object v = property.GetValue(formSectionData, null);
                    try
                    {
                        int value = int.Parse(v.ToString());
                        sBuilder.Append("," + value);
                    }
                    catch
                    {
                        throw new Exception("Invalid value at " + property.Name);
                    }
                }
            }

            return sBuilder.ToString();
        }

        //private static string GetVidokezoVyaHatariSegment(string ageCategoryKeyword, string segmentPrefix,
        //    ANCForm_VidokezoVyaHatari form)
        //{
        //    return string.Format("{0},{1}4,{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12}",
        //        ageCategoryKeyword, segmentPrefix,
        //        form.C_4a, form.C_4b, form.C_4c, form.C_4d, form.C_4e, form.C_4f, form.C_4g,
        //        form.C_4h, form.C_4i, form.C_4j, form.C_4k);
        //}

        //private static string GetPMTCTSegment(string ageCategoryKeyword, string segmentPrefix,
        //    ANCForm_PMTCT form)
        //{
        //    return string.Format("{0},{1}5,{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14}",
        //        ageCategoryKeyword, segmentPrefix,
        //        form.C_5a, form.C_5b, form.C_5c, form.C_5d, form.C_5e, form.C_5f, form.C_5g,
        //        form.C_5h, form.C_5i, form.C_5j, form.C_5k, form.C_5l, form.C_5m);
        //}

        //private static string GetMalariaSegment(string ageCategoryKeyword, string segmentPrefix,
        //    ANCForm_Malaria form)
        //{
        //    return string.Format("{0},{1}6,{2},{3},{4},{5},{6}",
        //        ageCategoryKeyword, segmentPrefix,
        //        form.C_6a, form.C_6b, form.C_6c, form.C_6d, form.C_6e);
        //}
        #endregion

        private void Method(Button targetButton)
        {
            var facility = cboFacility.SelectedItem as DataModels.Models.Facility;
            if (facility == null)
            {
                MessageBox.Show("Please select facility", AppConfiguration.ApplicationName,
                    MessageBoxButton.OK, MessageBoxImage.Stop);
                cboFacility.Focus();
                return;
            }

            var month = cboReportMonth.SelectedValue as int?;
            if (!month.HasValue)
            {
                MessageBox.Show("Please select month", AppConfiguration.ApplicationName,
                    MessageBoxButton.OK, MessageBoxImage.Stop);
                cboReportMonth.Focus();
                return;
            }

            var year = cboReportYear.SelectedValue as int?;
            if (!year.HasValue)
            {
                MessageBox.Show("Please select month", AppConfiguration.ApplicationName,
                    MessageBoxButton.OK, MessageBoxImage.Stop);
                cboReportMonth.Focus();
                return;
            }

            try
            {
                gettingReport = true;
                backgroundWorker.RunWorkerAsync();
                targetButton.Content = "Please wait...";
                targetButton.IsEnabled = false;
                var args = new InteroperableUserControlEventArgs
                {
                    StatusText = "Please wait...",
                    Type = InteroperableUserControlEventArgs.StatusType.Text
                };
                if (StatusChanged != null) StatusChanged(this, args);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, AppConfiguration.ApplicationName,
                    MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void btnGetReport_Click(object sender, RoutedEventArgs e)
        {
            Method(btnGetReport);
        }

        private void btnReset_Click(object sender, RoutedEventArgs e)
        {
            Method(btnReset);
        }

        private void btnRetryLoadingRegions_Click(object sender, RoutedEventArgs e)
        {
            btnRetryLoadingRegions.Visibility = Visibility.Collapsed;

            lblProgress.HorizontalContentAlignment = HorizontalAlignment.Center;
            lblProgress.Content = "Loading Data. Please wait...";
            lblProgress.FontWeight = FontWeights.Bold;
            lblProgress.Foreground = Brushes.Black;

            progressBar.Visibility = Visibility.Visible;
            loadingRegions = true;
            backgroundWorker.RunWorkerAsync();
            var args = new InteroperableUserControlEventArgs
            {
                StatusText = "Loading Data. Please wait...",
                Type = InteroperableUserControlEventArgs.StatusType.Text
            };
            if (StatusChanged != null) StatusChanged(this, args);
        }

        #region For operations when included in the parent control
        public void SaveChanges()
        {
            btnSave_Click(null, null);
        }

        public void Reset()
        {
            btnReset_Click(null, null);
        }
        #endregion

        private void cboFacility_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (gridActionPanel.Visibility == System.Windows.Visibility.Visible) LoadEmptyForm();
        }

        private void cboReportMonth_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (gridActionPanel.Visibility == System.Windows.Visibility.Visible) LoadEmptyForm();
        }

        private void btnClearForm_Click(object sender, RoutedEventArgs e)
        {
            if (gridActionPanel.Visibility == System.Windows.Visibility.Visible) LoadEmptyForm();
        }

        private void LinkIndicatorsWithinForm()
        {
            if (this.DataContext != null)
            {
                var datasource = this.DataContext as FullLDMTUHAReport;
                if (datasource != null)
                {
                    var under20Data = datasource.Under20Form;
                    var above20Data = datasource.Above20Form;

                    under20Data.PropertyChanged += LDForm_PropertyChanged;
                    above20Data.PropertyChanged += LDForm_PropertyChanged;
                }
            }
        }

        void LDForm_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "C_1")
            {
                var form = sender as LDForm;
                if (form != null)
                {
                    if (form.C_1.HasValue)
                    {
                        form.LDForm_TaarifaYaWaliojifungua.External_WaliotarajiwaKujifungua = form.C_1.Value;
                    }
                }
            }
        }

        private void TextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            var textBox = e.OriginalSource as TextBox;
            if (textBox != null)
            {
                textBox.SelectAll();
                int row = Grid.GetRow(textBox);
                foreach (UIElement element in grid.Children)
                {
                    int r = Grid.GetRow(element);
                    if (r == row)
                    {
                        var control = element as Control;
                        if (control != null) control.Background = Brushes.LightYellow;
                    }
                    if (r > row) break;
                }
            }
        }

        private void TextBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            var textBox = e.OriginalSource as TextBox;
            if (textBox != null)
            {
                int row = Grid.GetRow(textBox);
                foreach (UIElement element in grid.Children)
                {
                    int r = Grid.GetRow(element);
                    if (r == row)
                    {
                        var control = element as Control;
                        if (control != null) control.ClearValue(Control.BackgroundProperty);
                    }
                    if (r > row) break;
                }
            }
        }
    }
}
